/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "ohos_init.h"
#include "transmission.h"
#include "common.h"
//#include "softbus_device_report.h"

#include "session.h"
#include "client_trans_session_service.h"
#include "softbus_common.h"
#include "softbus_bus_center.h"
#include "utils_log.h"

// static sem_t g_sessionSem;
const char *g_sessionNameTest = "kaihong.jihong.test";

#define MAC_SIZE 6

#define MAX_FOUND_DEVICE_NUM 32

#define MAC_STR "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAC_ADDR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]

static IKHSessionCallback *g_callback = NULL;

static int OnSessionOpenedTest(int sessionId, int result)
{
    printf("\n>>>OnSessionOpened sessionId = %d, result = %d.\n", sessionId, result);
    if(result != 0){
        printf(">>>OnSessionOpened failed !!!!!!!!!!!!! \n");
    }
    return 0;
}

static void OnSessionClosedTest(int sessionId)
{
    printf("\n>>>OnSessionClosed sessionId = %d.\n", sessionId);
}

static void OnBytesReceivedTest(int sessionId, const void *data, unsigned int dataLen)
{
    printf("\n>>>OnBytesReceived sessionId = %d, data = %s.\n", sessionId, (char *)data);
    if (g_callback != NULL && g_callback->OnBytesReceived != NULL) {
        g_callback->OnBytesReceived(sessionId, data, dataLen);
    }
}

static void OnMessageReceivedTest(int sessionId, const void *data, unsigned int dataLen)
{
    printf("\n>>>OnMessageReceived sessionId = %d, data = %s \n", sessionId, (char *)data);
    if (g_callback != NULL &&  g_callback->OnMessageReceived != NULL) {
        g_callback->OnMessageReceived(sessionId, data, dataLen);
    }
}

void OnStreamReceivedTest(int sessionId, const StreamData *data, const StreamData *ext,
        const StreamFrameInfo *param)
{
    printf("\n>>>OnStreamReceived sessionId = %d, data = %s, ext = %s\n", sessionId, data->buf, ext->buf);
}

// void T_SendMessage(void) // GetInputNumber 输入sessionId
// {
//     int sessionId;
//     char data[DATA_SIZE] = {0};
//     sessionId = GetInputNumber("Please input session Id:");
//     GetInputString("Please input data to SendMessage:", data, DATA_SIZE);
//     int ret = SendMessage(sessionId, data, strlen(data) + 1);
//     printf("sendText:%s\n", data);
//     if (ret != 0) {
//         printf("SendMessage fail, ret = %d\n", ret);
//     } else {
//         printf("SendMessage ok\n");
//     }
// }

int TestSendMessage(const char *networkId, const char *msg, unsigned int msgLen)
{
    if (networkId == NULL || msg == NULL || msgLen <= 0) {
        printf("TestSendMessage param failed \n");
        LOG_TO_FILE("TestSendMessage param failed");
        return -1;
    }
    printf("TestSendMessage-------------------------------------\r\n");
    int sessionId = TestOpenSession(networkId, TYPE_MESSAGE);
    if (sessionId < 0) {
        printf("OpenSession type message failed, sessiond [%d]\n", sessionId);
        LOG_TO_FILE("OpenSession type message failed, sessiond [%d]\n", sessionId);
        return sessionId;
    }

    int ret = SendMessage(sessionId, msg, msgLen);
    if (ret < 0) {
        printf("SendMessage type bytes failed, ret [%d]\n", ret);
        LOG_TO_FILE("SendMessage type bytes failed, ret [%d]\n", ret);
        CloseSession(sessionId);
    }
    return ret;
}

int TestSendBytes(const char *networkId, const char *data, unsigned int dataLen)
{
    if (networkId == NULL || data == NULL || dataLen <= 0) {
        printf("TestendBytes param failed \n");
        LOG_TO_FILE("TestendBytes param failed");
        return -1;
    }

    int sessionId = TestOpenSession(networkId, TYPE_BYTES);
    if (sessionId < 0) {
        printf("OpenSession type bytes failed, sessiond [%d]\n", sessionId);
        LOG_TO_FILE("OpenSession type bytes failed, sessiond [%d]", sessionId);
        return sessionId;
    }

    int ret = SendBytes(sessionId, data, dataLen);
    if (ret < 0) {
        printf("SendBytes type bytes failed, ret [%d]\n", ret);
        LOG_TO_FILE("SendBytes type bytes failed, ret [%d]", ret);
        CloseSession(sessionId);
    }
    
    return ret;
}

int TestSendBytesToAll(const char *data, unsigned int dataLen)
{
    if (data == NULL || dataLen <= 0) {
        printf("TestSendBytesToAll param failed \n");
        LOG_TO_FILE("TestSendBytesToAll param failed");
        return -1;
    }

    int32_t onlineNum;
    NodeBasicInfo *info = NULL;
    int ret = GetAllNodeDeviceInfo(PKG_NAME, &info, &onlineNum);
    if (ret != 0 || info == NULL) {
        printf("GetAllNodeDeviceInfo fail, ret = %d.\n", ret);
        LOG_TO_FILE("GetAllNodeDeviceInfo fail, ret = %d", ret);
        return -1;
    }
    for (int i = 0; i < onlineNum; i++) {
        ret = TestSendBytes(info[i].networkId, data, dataLen);
        if (ret != 0) {
            printf("send bytes failed, ret[%d]", ret);
            FreeNodeInfo(info);
            return ret;
        }
    }
    FreeNodeInfo(info);
    return ret;
}

// void T_SendBytes(void)
// {    
//     int sessionId;
//     char data[DATA_SIZE] = {0};
//     sessionId = GetInputNumber("Please input session Id:");
//     GetInputString("Please input data to SendBytes:", data, DATA_SIZE);
//     int ret = SendBytes(sessionId, data, strlen(data) + 1);
//     if (ret != 0) {
//         printf("SendBytes fail, ret = %d\n", ret);
//     } else {
//         printf("SendBytes ok\n");
//     }
// }

void T_SendStreamTest(void)
{
    int sessionId;
    char data[DATA_SIZE];
    StreamData d1 = {0};
    sessionId = GetInputNumber("Please input session Id:");
    GetInputString("Please input data to SendStream:", data, DATA_SIZE);
    d1.buf = data;
    d1.bufLen = strlen(data) + 1;
    StreamData d2 = {0};
    StreamFrameInfo tmpf = {0};

    int ret = SendStream(sessionId, &d1, &d2, &tmpf);
    if (ret != 0) {
        printf("SendStream fail, ret = %d\n", ret);
    } else {
        printf("SendStream ok\n");
    }
}

void RegisterSessionCallbackTest(IKHSessionCallback *callback)
{
    g_callback = callback;
}

int GetLocalDeviceIdTest(char *deviceId, unsigned int len)
{
    if (deviceId==NULL || len<UDID_BUF_LEN) {
        printf("GetLocalDeviceId param error.\n");
        LOG_TO_FILE("GetLocalDeviceId param error.");
        return -1;
    }

    NodeBasicInfo info;
    int ret = GetLocalNodeDeviceInfo(PKG_NAME, &info);
    if (ret != 0) {
        printf("GetLocalNodeDeviceInfo fail, ret = %d.\n", ret);
        LOG_TO_FILE("GetLocalNodeDeviceInfo fail, ret = %d", ret);
        return -1;
    }

    unsigned char udid[UDID_BUF_LEN] = {0};
    ret = GetNodeKeyInfo(PKG_NAME, info.networkId, NODE_KEY_UDID, udid, UDID_BUF_LEN);
    if (ret != 0) {
        printf("GetNodeKeyInfo NODE_KEY_UDID fail, ret = %d.\n", ret);
        LOG_TO_FILE("GetNodeKeyInfo NODE_KEY_UDID fail, ret = %d", ret);
        return -1;
    }

    printf("GetNodeKeyInfo NODE_KEY_UDID  %s\n", udid);
    (void)memcpy_s(deviceId, len, udid, UDID_BUF_LEN);
    return ret;
}

int GetAllOnlineNumTest(unsigned int *num)
{
    if(NULL == num) {
        printf("GetAllOnlineNum param error.\n");
        LOG_TO_FILE("GetAllOnlineNum param error");
        return -1;
    }

    NodeBasicInfo *info = NULL;
    uint32_t infoNum = 0;
    int ret = LnnGetAllOnlineNodeInfo(&info, &infoNum);
    if(ret != 0){
        printf("LnnGetAllOnlineNodeInfo infoNum fail, ret = %d.\n", ret);
        LOG_TO_FILE("LnnGetAllOnlineNodeInfo infoNum fail, ret = %d", ret);
        return -1;
    }//

    if(NULL != info){
        SoftBusFree(info);
        info = NULL;
    }//

    *num = infoNum;
    return 0;
}

int T_CreateSessionServerTest(void)
{
    static ISessionListener listener = {
        .OnSessionOpened = OnSessionOpenedTest,
        .OnSessionClosed = OnSessionClosedTest,
        .OnBytesReceived = OnBytesReceivedTest,
        .OnMessageReceived = OnMessageReceivedTest,
        .OnStreamReceived = OnStreamReceivedTest,
        .OnQosEvent = NULL
    };

    int ret = CreateSessionServer(PKG_NAME, g_sessionNameTest, &listener);
    if (ret != 0) {
        printf("CreateSessionServer fail, ret = %d.\n", ret);
        LOG_TO_FILE("CreateSessionServer fail, ret = %d", ret);
        return ret ;
    }
    printf("CreateSessionServer ok.\n");
    return ret;
}

int T_RemoveSessionServerTest(void)
{
    int ret = RemoveSessionServer(PKG_NAME, g_sessionNameTest);
    if (ret != 0) {
        printf("RemoveSessionServer fail, ret = %d.\n", ret);
        LOG_TO_FILE("RemoveSessionServer fail, ret = %d", ret);
    }
    return ret;
}

// void T_OpenSession(const char *networkId, SessionType type)
// {
//     SessionAttribute attr;
//     int sessionId;
//     (void)memset_s(&attr, sizeof(attr), 0, sizeof(attr));
//     attr.dataType = GetInputNumber("Please input session type(1 - TYPE_MESSAGE, 2 - TYPE_BYTES, 3 - TYPE_FILE, 4 - TYPE_STREAM):");
//     if (attr.dataType == TYPE_STREAM) {
//         attr.attr.streamAttr.streamType = RAW_STREAM;
//     }
//     attr.linkTypeNum = GetInputNumber("Please input linkType mode(0 - AUTO or [1, 4]):");
//     if (attr.linkTypeNum < 0 || attr.linkTypeNum > LINK_TYPE_MAX) {
//         printf("invalid linkType num = %d.", attr.linkTypeNum);
//         return;
//     }
//     for (int i = 0; i < attr.linkTypeNum; i++) {
//         printf("input orderlist[%d] of linkType\n",i);
//         attr.linkType[i] = GetInputNumber("(1 - WLAN 5G, 2 - WLAN 2G, 3 - WIFI P2P, 4 - BR):");
//     }
//     GetInputString("Please input network Id:", networkId, NETWORK_ID_BUF_LEN);
//     sessionId = OpenSession(g_sessionNameTest, g_sessionNameTest, networkId, "", &attr);
//     if (sessionId < 0) {
//         printf("OpenSession fail, sessionId = %d\n", sessionId);
//         return;
//     }
//     printf("OpenSession succ, sessionId = %d\n", sessionId);
// }

int TestOpenSession(const char *networkId, SessionType type)
{
    SessionAttribute attr;
    (void)memset_s(&attr, sizeof(attr), 0, sizeof(attr));
    attr.linkTypeNum = LINK_TYPE_MAX;
    attr.dataType = type;
    LinkType linkTypeList[LINK_TYPE_MAX] = {
        LINK_TYPE_WIFI_WLAN_5G,
        LINK_TYPE_WIFI_WLAN_2G,
        LINK_TYPE_WIFI_P2P,
        LINK_TYPE_BR,
    };
    (void)memcpy_s(attr.linkType, sizeof(attr.linkType), linkTypeList, sizeof(linkTypeList));
    int sessionId = OpenSession(g_sessionNameTest, g_sessionNameTest, networkId, "", &attr);
    if (sessionId < 0) {
        printf("OpenSession failed ret:%d.\n",  sessionId);
        LOG_TO_FILE("OpenSession failed ret:%d",  sessionId);
    }
    return sessionId;
}

void T_CloseSessionTest(void)
{
    int sessionId = GetInputNumber("Please input session Id to CloseSession:");
    CloseSession(sessionId);
    T_RemoveSessionServerTest();
}

void TestCloseSession(int sessionId)
{
    CloseSession(sessionId);
    T_RemoveSessionServerTest();
}